//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LitwareHR.Recruiting.Contract;
using Shp.Runtime.Common;
using Shp.Runtime.Sitka.ServiceAgent.Entities;
using Shp.Runtime.Sitka.ServiceAgent;
using Shp.Runtime.Contract;
using LitwareHR.Recruiting.DataModel.Sitka.Constants;
using Shp.Runtime.DataModel.Sitka;
using System.Threading;
using System.Globalization;
using Shp.Runtime.DataModel.Sitka.Constants;
using System.Collections.ObjectModel;
using Shp.Runtime.Sitka.ServiceAgent.CrossTenant;
using System.Collections;
using System.Configuration;

namespace LitwareHR.Recruiting.DataModel.Sitka
{
    public class RecruitingDataModel
    {
        private IRepositoryFactory repositoryFactory;

        private static int resumeSubmissionAge = GetResumeSubmissionAge();
        
        private static int GetResumeSubmissionAge()
        {
            try
            {
                int age;
                string config = ConfigurationManager.AppSettings["ResumeSubmissionAge"];
                if (! String.IsNullOrEmpty(config))
                {
                    if (Int32.TryParse(config, out age))
                    {
                        return age;
                    }
                }
            }
            catch
            {
            }

            return -30;
        }

        public RecruitingDataModel(IRepositoryFactory factory)
        {
            repositoryFactory = factory;
        }

        public RecruitingDataModel()
        {
            repositoryFactory = new GenericRepositoryFactory();
        }

        private Resume GenericExtensibleEntityToResume(GenericExtensibleEntity resumeSitka, Guid tenantId)
        {
            Resume resume = null;
            if (resumeSitka != null)
            {
                resume = new Resume();
                resume.Id = resumeSitka.Id;
                resume.AdditionalInfo = resumeSitka.GetFieldValue(ResumeEntityFields.AdditionalInfo);
                resume.Address = resumeSitka.GetFieldValue(ResumeEntityFields.Address);
                resume.ApplicantName = resumeSitka.GetFieldValue(ResumeEntityFields.ApplicantName);
                resume.ApplicantLastName = resumeSitka.GetFieldValue(ResumeEntityFields.ApplicantSurname);
                resume.PhoneNumber = resumeSitka.GetFieldValue(ResumeEntityFields.PhoneNumber);
                resume.PositionId = new Guid(resumeSitka.GetFieldValue(ResumeEntityFields.PositionId));
                resume.Upn = new Upn(resumeSitka.GetFieldValue(ResumeEntityFields.Upn));
                DateTime date;
                string strDate = resumeSitka.GetFieldValue(ResumeEntityFields.Date);
                if (DateTime.TryParse(strDate, Thread.CurrentThread.CurrentCulture, DateTimeStyles.AssumeUniversal, out date))
                {
                    resume.Date = date;
                }
                bool videoAvailable;
                if (bool.TryParse(resumeSitka.GetFieldValue(ResumeEntityFields.IsVideoAvailable), out videoAvailable))
                {
                    resume.IsVideoAvailable = videoAvailable;
                }
                bool videoUploaded;
                if (bool.TryParse(resumeSitka.GetFieldValue(ResumeEntityFields.IsVideoUploaded), out videoUploaded))
                {                    
                    resume.IsVideoUploaded = videoUploaded;
                }

                AddCustomFieldsToResume(tenantId, resume, resumeSitka);
            }
            return resume;
        }

        private void AddCustomFieldsToResume(Guid tenantId, Resume resume, GenericExtensibleEntity resumeSitka)
        {
            BaseDataModel dataModel = new BaseDataModel(repositoryFactory);
            EntityField[] list = dataModel.GetEntityDefFields(tenantId, Constants.EntityKinds.Position);
            foreach (EntityField entityField in list)
            {
                if (entityField.IsVisibleFromApplicationForm && resumeSitka.GetFieldValue(entityField.Name) != null)
                {
                    resume.Fields.Add(new LitwareHR.Recruiting.Contract.Field(entityField.Name, resumeSitka.GetFieldValue(entityField.Name)));
                }
            }
        }        
        
        public Resume GetResume(Guid resumeId, Guid tenantId)
        {
            Resume resume = null;
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.GetDataRepository(tenantId))
            {
                GenericExtensibleEntity resumeSitka = repository.GetById(resumeId);
                resume = GenericExtensibleEntityToResume(resumeSitka, tenantId);
            }
            return resume;
        }
        
        public void SubmitResume(Resume resume, Guid tenantId)
        {
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.GetDataRepository(tenantId))
            {
                GenericExtensibleEntity entity = new GenericExtensibleEntity(ResumeEntityFields.Kind, resume.Id);
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.AdditionalInfo, resume.AdditionalInfo));
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.Address, resume.Address));
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.ApplicantName, resume.ApplicantName));
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.ApplicantSurname, resume.ApplicantLastName));
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.PhoneNumber, resume.PhoneNumber));
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.Date, resume.Date.Date));
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.PositionId, resume.PositionId.ToString()));
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.Upn, resume.Upn.ToString()));
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.IsVideoAvailable, resume.IsVideoAvailable));
                entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(ResumeEntityFields.IsVideoUploaded, resume.IsVideoUploaded));

                foreach (LitwareHR.Recruiting.Contract.Field field in resume.Fields)
                {
                    entity.Fields.Add(new Shp.Runtime.Sitka.ServiceAgent.Entities.Field(field.Name,field.Value));
                }
                repository.Insert(entity);
            }
        }        

        public void AddVideoResume(Resume resume, Guid tenantId)
        {
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.GetDataRepository(tenantId))
            {
                GenericExtensibleEntity entity = repository.GetById(resume.Id);
                entity.SetFieldValue(ResumeEntityFields.IsVideoAvailable, true);
                repository.Update(entity);
            }
        }        

        public void SetErrorOnVideoResume(Resume resume, Guid tenantId)
        {
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.GetDataRepository(tenantId))
            {
                GenericExtensibleEntity entity = repository.GetById(resume.Id);
                entity.SetFieldValue(ResumeEntityFields.IsVideoUploaded, false);
                entity.SetFieldValue(ResumeEntityFields.IsVideoAvailable, true);
                repository.Update(entity);
            }
        }
        
        public SilverlightAccount GetSilverlightAccount(Guid tenantId)
        {
            SilverlightAccount account = null;
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {                
                GenericExtensibleEntity tenant = repository.GetById(tenantId);
                if (tenant != null)
                {
                    string accountId = tenant.GetFieldValue(TenantSilverligthFields.TenantSilverlightAccountIdField);
                    string accountKey = tenant.GetFieldValue(TenantSilverligthFields.TenantSilverlightAccountKeyField);
                    if (!String.IsNullOrEmpty(accountId) && !String.IsNullOrEmpty(accountKey))
                    {
                        account = new SilverlightAccount();
                        account.AccountId = accountId;
                        account.AccountKey = accountKey;
                        account.TenantAlias = tenant.GetFieldValue(TenantSilverligthFields.TenantAliasField);
                    }
                }
            }
            return account;
        }        

        public Resume[] SearchResumes(PropertyFilter[] filters, Guid tenantId)
        {
            string whereCondition = SitkaQueryBuilder.GetSitkaQuery(filters, ResumeEntityFields.Kind);
            return SearchResumes(whereCondition, tenantId).ToArray();
        }
        
        public Resume[] SearchCrossTenantResumes(PropertyFilter[] filters, Guid tenantId)
        {
            //add condition date
            DateTime date = DateTime.Today.AddDays(resumeSubmissionAge);

            PropertyFilter dateFilter = new PropertyFilter(ResumeEntityFields.Date, PropertyType.DateTime, LogicalOperator.LessOrEqualThan, date.Date, LogicalConnector.And);
            dateFilter.SetSubFilters(filters, LogicalConnector.And);

            SystemDataModel systemDataModel = new SystemDataModel(this.repositoryFactory);
            Guid[] tenants = systemDataModel.GetAllTenantIds();
            
            List<string> tenantIds = new List<string>();
            foreach (Guid id in tenants)
            {
                if (id != tenantId)
                {
                    tenantIds.Add(id.ToString());
                }
            }

            IList<Resume> result = new Collection<Resume>();

            if (tenantIds.Count > 0)
            {
                string whereCondition = SitkaQueryBuilder.GetSitkaQuery(new PropertyFilter[] {dateFilter}, ResumeEntityFields.Kind);

                CrossTenantSearch<Resume> crossTenantSearch = new CrossTenantSearch<Resume>();
                result = crossTenantSearch.Search(tenantIds.ToArray(), new CrossTenantSearch<Resume>.SearchHandler(SearchHandler), whereCondition);
            }

            return result.ToArray();
        }

        protected IList<Resume> SearchHandler(string tenantId, string query)
        {
            return SearchResumes(query, new Guid(tenantId));
        }

        private IList<Resume> SearchResumes(string whereCondition, Guid tenantId)
        {
            IList<Resume> result = null;
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.GetDataRepository(tenantId))
            {
                result = new Collection<Resume>();
                IEnumerable<GenericExtensibleEntity> queryResult = repository.Search(whereCondition);
                foreach (GenericExtensibleEntity sitkaEntity in queryResult)
                {
                    result.Add(GenericExtensibleEntityToResume(sitkaEntity, tenantId));
                }
            }
            return result;
        }
    }
}
